package Controller

import (
	"backend/Dao"
	"backend/Service/dbService"
	"backend/Service/minioService"
	"backend/config"
	"backend/util"
	"fmt"
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"net/http"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type HomeWorkController struct{}

type newHomeWork struct {
	HomeworkName string `json:"homework_name"`
	EndTime      string `json:"end_time"`
	ClassId      int    `json:"class_id"`
	StartTime    string `json:"start_time"`
}

type reqSetNewHomeWork struct {
	HomeWorkName     string    `json:"homeWorkName"  example:"home_work_name"` // 作业名称
	EndTime          time.Time `json:"endTime" example:"end_time"`             // 结束时间
	StartTime        time.Time `json:"startTime" example:"start_time"`         // 开始时间
	HomeWorkDescribe string    `json:"homeWorkDescribe" example:"home_work_describe"`
	CurriculumId     int       `json:"curriculumId,string" example:"curriculum_id"`
}

// SetNewHomeWork
// @Summary 新增作业
// @Description 新增作业
// @Tags 帖子相关接口
// @Accept application/json
// @Produce application/json
// @Param tk header string false "Bearer 用户令牌"
// @Param object body reqSetNewHomeWork false "查询参数"
// @Security ApiKeyAuth
// @Success 200
// @Router /teacher/SetNewHomeWork [post]
func (this HomeWorkController) SetNewHomeWork(c *gin.Context) {

	var data = reqSetNewHomeWork{}
	_ = c.BindJSON(&data)

	util.Sout(data)
	homework := Dao.Homework{
		Model:            Dao.GetModel(),
		HomeworkName:     data.HomeWorkName,
		HomeworkDescribe: data.HomeWorkDescribe,
		EndTime:          data.EndTime,
		CurriculumId:     data.CurriculumId,
		StartTime:        data.StartTime,
	}
	dbService.DbConn.Create(&homework)
	var stus []struct {
		StuId int
	}
	dbService.DbConn.Model(&Dao.StudentCurriculum{}).Where("curriculum_id = ?", data.CurriculumId).Find(&stus)
	var setUpStuHmw []Dao.StuHomework
	for _, s := range stus {
		setUpStuHmw = append(setUpStuHmw, Dao.StuHomework{
			Model:      Dao.GetModel(),
			HomeworkId: int(homework.Model.ID),
			StuId:      s.StuId,
			Status:     0,
			Score:      0,
		})
	}
	dbService.DbConn.Create(&setUpStuHmw)
	c.JSON(200, homework.Model)
}

type resGetHomeWorkList struct {
	Dao.Homework
	CurriculumName string
}

//
// GetHomeWorkList
// @Description: 获取作业列表
// @author MaTaoXun 2022-01-15 17:11:06
// @return gin.HandlerFunc
//
func (this HomeWorkController) GetHomeWorkList(c *gin.Context) {

	rs := make([]resGetHomeWorkList, 0)
	var homeworkList []Dao.Homework
	dbService.DbConn.Find(&homeworkList)
	for _, homework := range homeworkList {
		curriculum := Dao.Curriculum{
			Model: Dao.Model{
				ID: uint(homework.CurriculumId),
			},
		}
		dbService.DbConn.Find(&curriculum)
		curriculumSeries := Dao.CurriculumSeries{
			Model: Dao.Model{
				ID: uint(curriculum.CurriculumSeriesId),
			},
		}
		dbService.DbConn.Find(&curriculumSeries)
		currName := curriculumSeries.CurriculumSeriesName + "-" + curriculum.CurriculumYear
		rs = append(rs, resGetHomeWorkList{
			Homework:       homework,
			CurriculumName: currName,
		})
	}
	c.JSON(200, rs)
}

// PageHomeWorkList
// @Summary 分页查询作业列表
// @Description 分页查询作业列表,获取
// @Tags 作业相关接口
// @Accept application/json
// @Produce application/json
// @Param tk header string false "token"
// @Param object body _reqPageHomeWorkList false "请求体"
// @Success 200 body _resPageHomeWorkList
// @Router /teacher/PageHomeWorkList [post]
func (this HomeWorkController) PageHomeWorkList(c *gin.Context) {
	data := _reqPageHomeWorkList{}
	_ = c.BindJSON(&data)
	rs := _resPageHomeWorkList{
		Count:        0,
		HomeWorkList: make([]_resPageHomeWorkList_Homeworklist_Item, 0),
	}
	if data.CurrInfo == "ALL" {
		// 没有课程筛选
		// 获取count
		dbService.DbConn.Find(&Dao.Homework{}).Count(&rs.Count)
		//获取作业信息
		var homeWorkList []Dao.Homework
		dbService.DbConn.Limit(data.PageSize).Offset((data.Page - 1) * data.PageSize).Order("id desc").Find(&homeWorkList)
		//作业中的所有课程信息
		currIds := make([]int, 0)
		for _, homework := range homeWorkList {
			currIds = append(currIds, homework.CurriculumId)
		}
		var currList []Dao.Curriculum
		dbService.DbConn.Where("id in ?", currIds).
			Select("id,curriculum_series_id,curriculum_year").Find(&currList)
		//作业中的所有课程信息中的所有课程系列信息
		currSerIds := make([]int, 0)
		for _, curriculum := range currList {
			currSerIds = append(currSerIds, curriculum.CurriculumSeriesId)
		}
		var currSerList []Dao.CurriculumSeries
		dbService.DbConn.Where("id in ?", currSerIds).
			Select("id,curriculum_series_name").Find(&currSerList)
		//key为课程系列id,值为课程系列名的map
		mapCurseridCursername := make(map[uint]string)
		for _, series := range currSerList {
			mapCurseridCursername[series.ID] = series.CurriculumSeriesName
		}
		//构造key为课程id,值为课程系列名-课程年份的map
		mapCurridCurrname := make(map[uint]string)
		for _, curr := range currList {
			mapCurridCurrname[curr.ID] = mapCurseridCursername[uint(curr.CurriculumSeriesId)] + "-" + curr.CurriculumYear
		}
		//课程数据导入rs
		for _, homework := range homeWorkList {
			rs.HomeWorkList = append(rs.HomeWorkList, _resPageHomeWorkList_Homeworklist_Item{
				Homework:       homework,
				CurriculumName: mapCurridCurrname[uint(homework.CurriculumId)],
			})
		}
	} else {
		// 有课程筛选
		split := strings.Split(data.CurrInfo, "_")
		if split[0] == "s" {
			//课程系列
			//获取课程系列下所有的课程
			curriculms := make([]Dao.Curriculum, 0)
			dbService.DbConn.Where("curriculum_series_id = ?", split[1]).Select("id,curriculum_year").
				Find(&curriculms)
			mapCurridCurrname := make(map[uint]string)
			series := Dao.CurriculumSeries{}
			dbService.DbConn.Select("curriculum_series_name").Where("id = ?", split[1]).First(&series)
			//获取这些课程下的作业,page
			currIds := make([]uint, 0)
			for _, curriculm := range curriculms {
				currIds = append(currIds, curriculm.ID)
				mapCurridCurrname[curriculm.ID] = series.CurriculumSeriesName + "-" + curriculm.CurriculumYear
			}
			homeworkList := make([]Dao.Homework, 0)
			dbService.DbConn.Where("curriculum_id in ?", currIds).Count(&rs.Count)
			dbService.DbConn.Where("curriculum_id in ?", currIds).Limit(data.PageSize).Offset((data.Page - 1) * data.PageSize).Order("id desc").Find(&homeworkList)
			for _, homework := range homeworkList {
				rs.HomeWorkList = append(rs.HomeWorkList, _resPageHomeWorkList_Homeworklist_Item{
					Homework:       homework,
					CurriculumName: mapCurridCurrname[uint(homework.CurriculumId)],
				})
			}

		} else {
			//课程
			dbService.DbConn.Where("curriculum_id = ?", split[1]).Count(&rs.Count)
			homeworkList := make([]Dao.Homework, 0)
			dbService.DbConn.Where("curriculum_id = ?", split[1]).Limit(data.PageSize).Offset((data.Page - 1) * data.PageSize).Order("id desc").Find(&homeworkList)
			var curriculumSeries []Dao.CurriculumSeries
			dbService.DbConn.
				Raw("select curriculum_series_name from curriculum_series where id in (select curriculum_series_id from curriculum where id = ?)",
					split[1]).Scan(&curriculumSeries)
			curriculum := Dao.Curriculum{}
			dbService.DbConn.First(&curriculum, "id = ?", split[1])
			for _, homework := range homeworkList {
				rs.HomeWorkList = append(rs.HomeWorkList, _resPageHomeWorkList_Homeworklist_Item{
					Homework:       homework,
					CurriculumName: curriculumSeries[0].CurriculumSeriesName + "-" + curriculum.CurriculumYear,
				})
			}
		}
	}
	c.JSON(200, rs)
}

type _reqPageHomeWorkList struct {
	Page     int    `json:"page,omitempty"`      //页码
	PageSize int    `json:"page_size,omitempty"` //页大小
	CurrInfo string `json:"curr_info,omitempty"` //课程信息"s_课程系列id"或者"c_课程id",全部写ALL
}
type _resPageHomeWorkList struct {
	Count        int64                                    `json:"count,omitempty,string"` //作业总数量
	HomeWorkList []_resPageHomeWorkList_Homeworklist_Item `json:"home_work_list,omitempty"`
}
type _resPageHomeWorkList_Homeworklist_Item struct {
	Dao.Homework
	CurriculumName string `json:"curriculum_name,omitempty"` //课程名称
}

type _resStuGetHomeWorkListItem struct {
	Dao.Homework
	CurriculumSeriesName string
	CurriculumYear       string
}

//
// StuGetHomeWorkList
// @Description: 学生获取有权限的作业列表
// @author MaTaoXun 2022-01-15 17:11:59
// @return gin.HandlerFunc
//
func (this HomeWorkController) StuGetHomeWorkList(c *gin.Context) {

	get, _ := c.Get("userId")
	getInt, _ := strconv.Atoi(get.(string))
	var stuHomeworks []Dao.StuHomework
	dbService.DbConn.Where(&Dao.StuHomework{StuId: getInt}).Find(&stuHomeworks)
	var rs []_resStuGetHomeWorkListItem
	homeWorkIds := make([]int, 0)
	for _, v := range stuHomeworks {
		homeWorkIds = append(homeWorkIds, v.HomeworkId)
	}
	dbService.DbConn.Model(Dao.Homework{}).
		Select("homework.*,curriculum.curriculum_year,curriculum_series.curriculum_series_name").
		Joins("left join curriculum on homework.curriculum_id = curriculum.id").
		Joins("left join curriculum_series on curriculum.curriculum_series_id = curriculum_series.id").
		Where("homework.id in ?", homeWorkIds).
		Find(&rs)
	c.JSON(200, rs)
}

//
// HomeWorkUpLoadFile
// @Description: 上传作业
// @author MaTaoXun 2022-01-15 17:12:28
// @return gin.HandlerFunc
//
func (this HomeWorkController) HomeWorkUpLoadFile(c *gin.Context) {

	// 单文件
	HomeworkId, _ := c.GetPostForm("HomeworkId")
	file, _ := c.FormFile("file")
	get, _ := c.Get("userId")
	stuId, _ := strconv.Atoi(get.(string))
	hmwId, _ := strconv.Atoi(HomeworkId)
	//验证时间是否过期
	var homework Dao.Homework
	dbService.DbConn.Where(&Dao.Homework{Model: Dao.Model{ID: uint(hmwId)}}).Find(&homework)
	onminute, _ := time.ParseDuration("1m")
	if time.Now().After(homework.EndTime.Add(onminute)) {
		c.JSON(http.StatusOK, "overdue")
		return
	}
	//通过stuid获取班级姓名
	student := Dao.Student{}
	dbService.DbConn.Select("stu_name,stu_class").Find(&student, "id = ?", stuId)
	open, _ := file.Open()
	err, m := minioService.UploadFile("homework", file.Filename, homework.HomeworkName+"/"+student.StuClass+student.StuName+"/", open)
	if err != nil {
		fmt.Println("UploadHomeWorkerr", err)
	}
	homeWorkFile := Dao.HomeworkFile{
		Model:      Dao.GetModel(),
		HomeworkId: hmwId,
		StuId:      stuId,
		Md5:        "",
		FileUrl:    m.Key,
	}
	dbService.DbConn.Create(&homeWorkFile)
	dbService.DbConn.Model(&Dao.StuHomework{}).Where("stu_id = ? and homework_id = ?", stuId, HomeworkId).Update("status", 1)
	c.JSON(http.StatusOK, "ok")
}

type reqGetHomeWorkFileListByStuIdAndHomeWorkId struct {
	HomeWorkId int `json:"HomeWorkId,string"`
}
type resGetHomeWorkFileListByStuIdAndHomeWorkId struct {
	Dao.HomeworkFile
	FileName string
}

//
// GetHomeWorkFileListByStuIdAndHomeWorkId
// @Description: 通过学生id和作业id获取作业文件
// @author MaTaoXun 2022-01-15 17:13:23
// @return gin.HandlerFunc
//
func (this HomeWorkController) GetHomeWorkFileListByStuIdAndHomeWorkId(c *gin.Context) {

	get, _ := c.Get("userId")
	StuId, _ := strconv.Atoi(get.(string))
	data := reqGetHomeWorkFileListByStuIdAndHomeWorkId{}
	err := c.BindJSON(&data)
	if err != nil {
		return
	}
	homeworkFile := Dao.HomeworkFile{
		HomeworkId: data.HomeWorkId,
		StuId:      StuId,
	}
	var homeworkFiles []Dao.HomeworkFile
	dbService.DbConn.Where(&homeworkFile).Find(&homeworkFiles)
	var rs []resGetHomeWorkFileListByStuIdAndHomeWorkId
	for _, file := range homeworkFiles {
		split := strings.Split(file.FileUrl, "_")

		rs = append(rs, resGetHomeWorkFileListByStuIdAndHomeWorkId{
			HomeworkFile: file,
			FileName:     split[len(split)-1],
		})
	}
	c.JSON(200, rs)
}

//
// GetHomeWorkFileByUrl
// @Description: 下载作业文件(代理)
// @author MaTaoXun 2022-01-15 17:14:13
// @return gin.HandlerFunc
//
func (this HomeWorkController) GetHomeWorkFileByUrl(c *gin.Context) {

	//ure := c.Query("url")
	//file, _ := minioService.GetFile(url, "homework")
	//c.Header("Content-Length", strconv.Itoa(len(file)))
	//c.Header("Content-Disposition", "attachment;")
	//c.Header("Content-Transfer-Encoding", "binary")
	//c.Data(http.StatusOK, "application/octet-stream", file)

	proxyUrl, _ := url.Parse("http://" + config.Config.Minio.Endpoint + "/homework")
	//fmt.Println(ure)
	proxy := util.GetPorxy(proxyUrl)
	c.Request.URL.Path = strings.ReplaceAll(c.Request.URL.Path, "/GetHomeWorkFileByUrl", "")
	//proxyUrl.Host = minioService.Endpoint
	//proxy := httputil.NewSingleHostReverseProxy(proxyUrl)
	//fmt.Println(c.Request.URL)
	proxy.ServeHTTP(c.Writer, c.Request)

	c.Abort()
}

type resGetHomeWorkFileAndStudentListById struct {
	Dao.HomeworkFile
	Dao.Student
	FileName   string
	CreateTime time.Time
}

//
// GetHomeWorkFileAndStudentListById
// @Description: 通过作业id和学生id获取已经交作业的文件
// @author MaTaoXun 2022-01-15 17:23:36
// @return gin.HandlerFunc
//
func (this HomeWorkController) GetHomeWorkFileAndStudentListById(c *gin.Context) {

	url, _ := strconv.Atoi(c.Query("id"))
	var homeworkFiles []Dao.HomeworkFile
	dbService.DbConn.Where(&Dao.HomeworkFile{HomeworkId: url}).Find(&homeworkFiles)
	var rs []resGetHomeWorkFileAndStudentListById
	for _, file := range homeworkFiles {
		split := strings.Split(file.FileUrl, "_")
		student := Dao.Student{}
		dbService.DbConn.Where(&Dao.Student{Model: Dao.Model{ID: uint(file.StuId)}}).Find(&student)
		rs = append(rs, resGetHomeWorkFileAndStudentListById{
			HomeworkFile: file,
			Student:      student,
			FileName:     split[len(split)-1],
			CreateTime:   file.Model.CreatedAt,
		})
	}

	c.JSON(http.StatusOK, rs)
}

//
// GetHomeWorkFileAndStudentListByHomeWorkId
// @Description: 通过作业id获取所有学生作业的状态
// @author MaTaoXun 2022-01-15 17:25:24
// @return gin.HandlerFunc
//
func (this HomeWorkController) GetHomeWorkFileAndStudentListByHomeWorkId(c *gin.Context) {

	url, err := strconv.Atoi(c.Query("id"))
	if err != nil {
		url = 1
	}
	var stuHomeworks []Dao.StuHomework
	dbService.DbConn.Where(&Dao.StuHomework{HomeworkId: url}).Find(&stuHomeworks)

	stuIds := make([]int, 0)
	for _, homework := range stuHomeworks {
		stuIds = append(stuIds, homework.StuId)
	}
	var stus []Dao.Student
	dbService.DbConn.Where("id in ?", stuIds).Find(&stus)
	stuMap := make(map[int]Dao.Student)
	for _, student := range stus {
		stuMap[int(student.Model.ID)] = student
	}

	// files
	var files []Dao.HomeworkFile
	dbService.DbConn.Where("homework_id = ?", url).Find(&files)
	fileMap := make(map[int][]string)
	for _, file := range files {
		urlList, has := fileMap[file.StuId]
		if has {
			fileMap[file.StuId] = append(urlList, file.FileUrl)
		} else {
			fileMap[file.StuId] = []string{file.FileUrl}
		}
	}

	var rs []interface{}
	for _, homework := range stuHomeworks {
		rs = append(rs, struct {
			StuHomeworkId int `json:"StuHomeworkId,string"`
			Dao.StuHomework
			Dao.Student
			FileList []string
		}{
			int(homework.Model.ID), homework, stuMap[homework.StuId], fileMap[homework.StuId],
		})
	}

	c.JSON(http.StatusOK, rs)
}

//
// WithdrawHomework
// @Description: 撤回作业
// @author MaTaoXun 2022-01-15 17:25:59
// @return gin.HandlerFunc
//
func (this HomeWorkController) WithdrawHomework(c *gin.Context) {

	userId, _ := c.Get("userId")
	userIdInt, _ := strconv.Atoi(userId.(string))
	id, _ := strconv.Atoi(c.Query("id"))
	h := &Dao.HomeworkFile{Model: Dao.Model{ID: uint(id)}}
	var s Dao.HomeworkFile
	dbService.DbConn.Where(h).Find(&s)
	if s.StuId == userIdInt {
		dbService.DbConn.Delete(h)
		c.String(http.StatusOK, "delSuccess")
	} else {
		c.String(http.StatusOK, "你的行为已通知管理员")
	}

}

//
// DeleteHomework
// @Description: 删除作业与作业文件(表中)
// @author MaTaoXun 2022-01-15 17:26:05
// @return gin.HandlerFunc
//
func (this HomeWorkController) DeleteHomework(c *gin.Context) {

	idStr := c.Query("id")
	id, _ := strconv.Atoi(idStr)
	dbService.DbConn.Transaction(func(tx *gorm.DB) error {
		tx.Delete(&Dao.Homework{Model: Dao.Model{ID: uint(id)}})
		tx.Where("homework_id = ?", id).Delete(&Dao.HomeworkFile{})
		return nil
	})

	c.String(200, "delSuc")
}

type reqChangeHomeWorksStu struct {
	HomeWorkId int      `json:"homeWorkId,string"`
	StuList    []string `json:"stuList"`
}

//
// ChangeHomeWorksStu
// @Description: 更改作业和学生绑定的信息
// @author MaTaoXun 2022-01-15 17:26:13
// @return gin.HandlerFunc
//
func (this HomeWorkController) ChangeHomeWorksStu(c *gin.Context) {

	data := reqChangeHomeWorksStu{}
	c.BindJSON(&data)
	var stuHomeWorks []Dao.StuHomework
	oldStuSet := make(map[int]struct{})
	newStuSet := make(map[int]struct{})
	delStuList := make([]string, 0)
	addStuList := make([]Dao.StuHomework, 0)
	dbService.DbConn.Where(Dao.StuHomework{HomeworkId: data.HomeWorkId}).Select("stu_id").Find(&stuHomeWorks)
	for _, v := range stuHomeWorks {
		oldStuSet[v.StuId] = struct{}{}
	}
	for _, v := range data.StuList {
		atoi, _ := strconv.Atoi(v)
		newStuSet[atoi] = struct{}{}
	}
	for _, v := range stuHomeWorks {
		if _, ok := newStuSet[v.StuId]; !ok {
			delStuList = append(delStuList, strconv.Itoa(v.StuId))
		}
	}
	for _, v := range data.StuList {
		atoi, _ := strconv.Atoi(v)
		if _, ok := oldStuSet[atoi]; !ok {

			addStuList = append(addStuList, Dao.StuHomework{
				Model:      Dao.GetModel(),
				HomeworkId: data.HomeWorkId,
				StuId:      atoi,
				Status:     0,
				Score:      0,
			})
		}
	}
	dbService.DbConn.Where("homework_id = ? and stu_id in ? ", data.HomeWorkId, delStuList).Where("").Delete(&Dao.StuHomework{})
	dbService.DbConn.Create(&addStuList)
}

//
// GetStuHomeWorkInfo
// @Description: 获取学生和作业绑定的全部初始化信息
// @author MaTaoXun 2022-01-23 18:49:21
// @return gin.HandlerFunc
//

type StuhmwElement struct {
	ClassID string        `json:"ClassId"`
	StuList []StuListItem `json:"StuListItem"`
}

type StuListItem struct {
	StuInfo StuInfo `json:"StuInfo"`
	IfCheck bool    `json:"IfCheck"`
}

type StuInfo struct {
	Id       int `json:"Id,string"`
	StuNum   string
	StuName  string
	StuClass string
}

func (this HomeWorkController) GetStuHomeWorkInfo(c *gin.Context) {

	var studentList []StuInfo
	dbService.DbConn.Model(&Dao.Student{}).Find(&studentList)

	var chooseStuList []struct {
		StuId  int
		Status int
		Score  int
	}
	dbService.DbConn.Model(&Dao.StuHomework{}).Where("homework_id = ?", c.Query("hmwId")).Find(&chooseStuList)
	chooseedMap := make(map[int]struct{})
	for _, s := range chooseStuList {
		chooseedMap[s.StuId] = struct{}{}
	}

	var stuList []StuListItem
	for _, info := range studentList {
		if _, exist := chooseedMap[info.Id]; exist {
			stuList = append(stuList, StuListItem{
				StuInfo: info,
				IfCheck: true,
			})
		} else {
			stuList = append(stuList, StuListItem{
				StuInfo: info,
				IfCheck: false,
			})
		}
	}

	rsMap := make(map[string][]StuListItem)
	for _, listItem := range stuList {
		list, exist := rsMap[listItem.StuInfo.StuClass]
		if exist {
			rsMap[listItem.StuInfo.StuClass] = append(list, listItem)
		} else {
			rsMap[listItem.StuInfo.StuClass] = append(make([]StuListItem, 0), listItem)
		}
	}

	var rsStruct []StuhmwElement
	for s, items := range rsMap {
		rsStruct = append(rsStruct, StuhmwElement{
			ClassID: s,
			StuList: items,
		})
	}
	c.JSON(200, rsStruct)
}

func (this HomeWorkController) SetScore(c *gin.Context) {

	data := struct {
		Score int `json:"score,string"`
		Id    int `json:"Id,string"`
	}{}
	c.BindJSON(&data)
	dbService.DbConn.Model(&Dao.StuHomework{}).Where("id = ?", data.Id).Updates(Dao.StuHomework{Score: data.Score, Status: 2})
	c.JSON(200, "score success")
	//dbService.DbConn.Model(&Dao.StuHomework{}).Where()
}
